/**
 * console.log()
 */
function console_log () {
  // 传入一个变量
  const a = 1
  console.log(a)
  // => 1

  // 传入一个对象
  const f00 = { a: 1 }
  console.log(f00)
  // => {a: 1}

  // 传入多个变量
  console.log(a, f00)
  // => 1 {a: 1}

  // 传入特定的占位符来对比参数进行格式化处理
  const string = 'Glory of Kings'
  const number = 100
  const float = 9.5
  const obj = { name: 'Monkey King' }

  // %s 字符串占位符
  console.log('I do like %s', string)
  // => I do like Glory of Kings

  // %d 整数占位符
  console.log('I won %d times', number)
  // => I won 100 times

  // %f 浮点数占位符
  console.log('My highest score is %f', float)
  // My highest score is 9.5

  // %o 对象占位符
  console.log('My favorite hero is %o', obj)
  // My favorite hero is {name: "Monkey King"}

  // %c css样式占位符
  console.log('I do like %c%s', 'padding: 2px 4px; background: orange; color: white; border-radius: 4px', string)
  // 样式占位符图片url(暂无)

}

console_log()

/**
 * console.warn()
 */
function console_warn () {
  // 打印的信息属于警告级别，左侧会有一个黄色三角感叹号
  console.warn('警告!警告!警告!')
  // <黄色三角感叹号>警告!警告!警告!
}

console_warn()

/**
 * console.dir()
 */
function console_dir () {
  // 主要用于打印对象，可展开查阅对象的详细信息。常用于输出DOM节点
  console.dir(document.body)
  // 可展开的<body>
}

console_dir()

/**
 * console.table()
 */
function console_table () {
  const response = [
    {
      id: 1,
      name: 'Lucy',
      age: 22,
      sex: 0
    },
    {
      id: 2,
      name: 'Jack',
      age: 23,
      sex: 1
    }
  ]
  // 常规打印
  console.log(response)

  // table打印
  console.table(response)
}

console_table()

/**
 * console.assert()
 */
function console_assert () {
  const arr = [1, 2, 3, 4, 5]
  // assert()接收多个参数，只有当第一个参数返回false时，才会打印后续参数。并且输出为error级别
  console.assert(arr.length !== 5, 'arr.length 不等于5')
  console.assert(arr.length !== 5, 'arr.length 不等于5,更多测试：%o', arr)
  console.assert(arr.length === 5, 'arr.length 等于5')
}

console_assert()

/**
 * console.trace()
 */
function console_trace () {
  // 打印出发生错误的原始错误点。
  // 可以看到自下而上的一条调用路径，并可以快速判定是在bar2函数中传入了不合适的参数null而导致出错，方便我们跟踪发生错误的原始位置。
  function foo (data) {
    if (data === null) {
      console.trace()
      return []
    }
    return [data.a, data.b]
  }
  function bar1 (data) {
    return foo(data)
  }
  function bar2 (data) {
    return foo(data)
  }

  bar1({a: 1, b: 2})
  bar2()
}

// 会导致后续代码停止执行
// console_trace()

/**
 * console.count()
 */
function console_count () {
  for (let i = 0; i <= 5; i++) {
    if (!(i % 2)) {
      console.count('even')
    } else {
      console.count('odd')
    }
  }
}

console_count()

/**
 * console.time() & console.timeEnd()
 */
function console_time () {
  // 传统计算执行时间方式
  const startTime = performance.now();
  let sum = 0;
  for(let i = 0;i < 100000;i++) {
      sum += i;
  }
  const diffTime = performance.now() - startTime;
  console.log(`Execution time: ${ diffTime }`);

  // console.time() & console.timeEnd()
  // 这种方式更优雅，更少的临时变量且没有做任何计算
  console.time('sum2');
  let sum2 = 0;
  for(let i = 0;i < 100000;i++) {
      sum2 += i;
  }
  console.timeEnd('sum2');
}

console_time()

/**
 * console.group() & console.groupEnd()
 */
function console_group () {
  // class MyClass {
  //   constructor() {
  //     console.group('Constructor')
  //     console.log('Constructor executed')
  //     this.init()
  //     console.groupEnd()
  //   }
  
  //   init() {
  //     console.group('init')
  //     console.log('init executed')
  //     console.groupEnd()
  //   }
  // }
  // const myClass = new MyClass()
  function init () {
    console.group('init')
    console.log('function init')
    console.groupEnd()
  }
  console.group('window')
  console.log('function group')
  init()
  console.groupEnd()

  // 引申:折叠分组信息
  console.groupCollapsed()
  console.log('collapsed')
  console.log('collapsed2')
  console.groupEnd()
  console.log('end end')
}

console_group()

/**
 * 将指定dom变成可编辑状态
 */
function contentEditable () {
  document.body.contentEditable = true
}

contentEditable()

/**
 * Chrome Command Line API
 * 只能在F12控制台中使用,JavaScript无法调用 
 */
function ChromeCommandAPI () {
  return 'Can not used in JavaScript'

  // 1. 选择DOM元素
  // $(selector)：返回匹配指定CSS选择器的DOM元素的第一个引用,相当于document.querySelector()函数。
  $('body')
  // $$(selector)：返回匹配指定CSS选择器的DOM元素数组,相当于document.querySelectorAll()函数。
  $$('div')
  // $x(path)：返回一个与给定XPath表达式匹配的DOM元素数组。
  $x('//p[a]')

  // 2. 检索最后一个结果的值
  // $_

  // 3. 查找与指定DOM元素关联的事件
  getEventListeners($('selector'))
  // 如果我们需要找到某个特定的事件监听器，可以通过如下方式进行访问
  // eventName表示对应的事件类型
  // index表示该事件类型下的事件监听器数组的索引
  getEventListeners($('selector')).eventName[index].listener
  // 例如获取document下click事件监听器数组的第一项
  getEventListeners(document).click[0].listener

  // 4. 监控事件(https://user-gold-cdn.xitu.io/2019/11/29/16eb305a50a68c88?imageslim)
  // 将监视与选择器匹配的元素关联的所有事件，当这些事件被触发时会将它们打印到控制台。例如monitorEvents($('#content'))将监视id为content的元素关联的所有事件。
  monitorEvents($('selector'))
  // 将监视选择器匹配的元素的某个特定的事件。 例如，monitorEvents($('#content'), 'click')将监视id为content的元素关联的click事件。
  monitorEvents($('selector'), 'eventName')
  // 将监视选择器匹配的元素的某些特定的事件。与上述不同的是，第二项可以传入一个字符串数组，包含所有需要监听的事件类型名称，以此达到自定义监听的目的。例如monitorEvents($('#content'), ['click', 'focus'])将监视id为content的元素关联的click和focus事件。
  // monitorEvents($('selector'), [eventName1, eventName2, ...])
  // 将停止监视选择器匹配的元素关联的所有事件。例如unmonitorEvents($('#content'))将停止监视id为content的元素关联的所有事件。
  unmonitorEvents($('selector'))

  // 5. 检查DOM元素(https://user-gold-cdn.xitu.io/2019/11/29/16eb31a55f112adb?imageslim)
  // 将检查与选择器匹配的元素，并且会自动跳转到Chrome Developer Tools的Elements选项卡中。例如inspect($('#content'))将检查id为content的元素。
  inspect($('selector'))
}

ChromeCommandAPI()
